#include "cacheCentral.h"
#include "cachePage.h"

qSpan* centralCache::GetOneSpan(size_t idx, size_t size_class)
{
    qSpan* it = span_list_[idx].begin();
    while(it != span_list_[idx].end())
    {
        if(it->list_)
            return it;
        it = it->next_;
    }

    qSpan* sp = PageCache::getInstance()->getSpan(sizeClass::SizeMovePage(size_class));
    if(!sp)
        return nullptr;

    //std::cout << "获得span: " << sp << std::endl;

    sp->size_ = size_class; 
    //切割span，并不是真正的切开拿出去，而是在每个内存块里保存下一个内存块的地址
	//页号和地址相互转化
	//得到当前页的起始地址，一定会是起始地址，因为是一整页一整页给的
    uintptr_t start_addr = static_cast<uintptr_t>(sp->pageid_ << PAGE_SHIFT);
    uintptr_t end_addr = start_addr + static_cast<uintptr_t>(sp->pagenum_ << PAGE_SHIFT);

    char* start = reinterpret_cast<char*>(start_addr);
    char* end = reinterpret_cast<char*>(end_addr);
    while(start < end)
    {
        NextObj(reinterpret_cast<void*>(start)) = sp->list_;
        sp->list_ = start;
        start = start + sp->size_;//所以需要是char*类型
    }

    // for(size_t i = 0; i < sp->pagenum_; ++i)
    // {
    //     void* start = reinterpret_cast<void*>((sp->pageid_ + i) << PAGE_SHIFT);
    //     NextObj(start) = sp->list_;
    //     sp->list_ = start;
    // }

    span_list_[idx].pushFront(sp);
    return sp;
}

size_t centralCache::fetchRangeObj(void*& start, void*& end, size_t num, size_t size_class)
{
    if(!num)
        return 0;

    size_t idx = sizeClass::getIndex(size_class);
    std::lock_guard<std::mutex> lc(span_list_[idx].getMutex());

    qSpan* span = GetOneSpan(idx, size_class);
    if(!span || span->list_ == nullptr)
        return 0;
    

    size_t n = 0;
    void* cur = span->list_;
    start = cur;
    while(n < num && cur)
    {
        end = cur;
        cur = NextObj(cur);
        n++;
        span->usenum_++;
    }
    span->list_ = cur;
    NextObj(end) = nullptr;
    //std::cout << "申请数量：" << num << ":" << n << ":" <<span->usenum_ << std::endl;
    return n;
}

void centralCache::releaseRangeObj(void* start, size_t size_class)
{
    size_t idx = sizeClass::getIndex(size_class);

    std::lock_guard<std::mutex> lc(span_list_[idx].getMutex());

    while (start)
    {
        qSpan* sp = PageCache::getInstance()->getSpanByPageid(start);
        if(sp)
        {
            // count++;
            // std::cout << count << std::endl;
            void* next = NextObj(start);
            NextObj(start) = sp->list_;
            sp->list_ = start;
            if(sp->usenum_ > 0)
                sp->usenum_--;
            else 
                //std::cout << start << ": usenum: " << sp->usenum_ << std::endl;

            if(sp->usenum_ == 0)
            {
                //std::cout << "releaseRangeObj: " << sp << std::endl;
                //归还给pageCache
                if(span_list_[idx].erase(sp))
                {
                    //std::cout << "归还span: " << sp << std::endl;
                    sp->list_ = nullptr;
                    PageCache::getInstance()->releaseSpan(sp);
                }
            }
            start = next;
        }
        else
        {
            break;
        }
    }
}